#include <QApplication> 
#include <QAction> 
#include <QMenu>
#include <QSettings>
#include <QStandardPaths>
#include <QDBusReply> 
#include <QDBusArgument>
#include <QDBusMetaType> 
#include <QDBusInterface>
#include <QDBusConnection>
#include <QDebug>
#include <QVariant>
#include "fcitx-dbus.h"

#define SHOWICON

namespace  {
    QString defaultIM;
#ifdef SHOWICON
    QString const get_icon_name(QString const &im);
#endif
    QDBusInterface *fcitx_dbus_inf1;
#ifndef USEINI
    QDBusInterface *fcitx_dbus_inf2;
#endif
    void onActionChanged(QAction *action) {
        fcitx_dbus_inf1->call("SetCurrentIM", action->data().toString());
        qDebug() << "SetCurrentIM:" << action->data().toString();
    }
    struct DBusIMData {
        QString lname;
        QString name;
        QString lang;
        bool    enabled;
    };

}

namespace {
#ifdef SHOWICON
    QString const get_icon_name(QString const &im) {
        if(im.startsWith("fcitx-keyboard-"))  {
            defaultIM = im;
            return QString("active");
        }
        if(im == "sogouimebs") return QString("sogoupinyin");
        return im;
    }
#endif
}


//注册时必须同时定义输入/输出流
static QDBusArgument &operator<<(QDBusArgument &argument, const DBusIMData &im) {
    argument.beginStructure();
    argument << im.lname << im.name << im.lang << im.enabled;
    argument.endStructure();
    return argument;
}

// Retrieve the DBusIMData data from the D-Bus argument
static const QDBusArgument &operator>>(const QDBusArgument &argument, DBusIMData &im)
{
    argument.beginStructure();
    argument >> im.lname >> im.name >> im.lang >> im.enabled;
    argument.endStructure();
    return argument;
}

//构造a{sv}参数
static QDBusArgument &operator<<(QDBusArgument &argument, const ArgPlaceholder &arg) {
    qDebug() <<"QDBusArgument &QDBusArgument::" <<  __func__ << 
               "(QDBusArgument &argument, const ArgPlaceholder &arg)";
    argument.beginMap(qMetaTypeId<QString>(), qMetaTypeId<QDBusVariant>());
    argument.endMap();
    return argument;
}

static const QDBusArgument &operator>>(const QDBusArgument &argument, ArgPlaceholder &arg)
{
    qDebug() <<"const QDBusArgument &QDBusArgument::" <<  __func__ << 
               "(const QDBusArgument &argument, ArgPlaceholder &arg)";
    return argument;
}


Q_DECLARE_METATYPE(DBusIMData) //qMetaTypeId<DBusIMData>() for qDBusRegisterMetaType
Q_DECLARE_METATYPE(ArgPlaceholder) //qMetaTypeId<DBusIMData>() for qDBusRegisterMetaType
typedef QList<DBusIMData> DBusIMDataList;
//Q_DECLARE_METATYPE(DBusIMDataList)
//Q_DECLARE_METATYPE(QDBusArgument)
// Marshall the DBusIMData data into a D-Bus argument

int main(int argc, char *argv[]) {
    //qRegisterMetaType<DBusIMData>(); //仅Qt属性系统需要
    //qRegisterMetaType<DBusIMDataList>();
    qDBusRegisterMetaType<DBusIMData>();
    qDBusRegisterMetaType<ArgPlaceholder>();
    //qDBusRegisterMetaType<DBusIMDataList>();
    QApplication a(argc, argv);

    fcitx_dbus_inf1 = new QDBusInterface(FCITX_DBUS_SERVICE, FCITX_DBUS_PATH, QString(FCITX_DBUS_INF));
#ifdef USEINI
    QString confPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation));
    qDebug() <<  confPath;
    QSettings settings(confPath+"/fcitx/profile", QSettings::IniFormat);
    settings.beginGroup("Profile");
    QString curIm(settings.value("IMName").toString());
    QStringList enabledIMList(settings.value("EnabledIMList").toStringList());
    settings.endGroup();
#else
    QDBusReply<QString> reply1 = fcitx_dbus_inf1->call("GetCurrentIM");
    QDBusMessage rmsg1 = fcitx_dbus_inf1->call("GetCurrentIM");
    qDebug() << rmsg1.arguments().at(0);
    qDebug() << rmsg1.arguments().at(0).value<QString>();
    QString curIm(reply1.value());
    fcitx_dbus_inf2 = new QDBusInterface(FCITX_DBUS_SERVICE, FCITX_DBUS_PATH, DBUS_PROP_INF);
    qDebug()<<"fcitx_dbus_inf2->isValid():" << fcitx_dbus_inf2->isValid();
    QDBusMessage reply2 = fcitx_dbus_inf2->call("Get", FCITX_DBUS_INF, "IMList");
    if(reply2.type() != QDBusMessage::ReplyMessage)
        qDebug() << reply2.errorMessage();

    qDebug() << reply2.arguments().at(0);
    QDBusVariant const &dvar = reply2.arguments().at(0).value<QDBusVariant>();
    QDBusArgument const &arg = dvar.variant().value<QDBusArgument>();
    qDebug() << arg.currentType(); //2: array
    DBusIMDataList enabledIMList;
    arg.beginArray();
    while(!arg.atEnd()) {
        DBusIMData im;
        arg >> im; //这里也可以使用QDBusArgument::beginStructure直接解析而无需定义QDBusArgument和DBusIMData的转换函数
        if(im.enabled) enabledIMList << im;
        //qDebug() << im.lname;

    }
    arg.endArray();
#endif 

    QMenu *actionMenu = new QMenu("EIM"); //enalbed IM menu
    QActionGroup *actionGroup = new QActionGroup(nullptr);
    QString icon_path("/usr/share/fcitx/skin/default/%1.png");
    for(auto im : enabledIMList) {
#ifdef USEINI
        QStringList im_pair(im.split(':'));
        //qDebug() << "IM:" << im_pair[0] << ", Status:" << im_pair[1] << endl;
        if(im_pair[1] == "False") continue;
        QString im_name(im_pair[0]);
        QString im_lname(im_pair[0]);
#else
        QString im_name(im.name);       
        QString im_lname(im.lname);       
#endif
#ifdef SHOWICON
        QIcon icon(icon_path.arg(get_icon_name(im_name)));
        QAction *ima = new QAction(icon, im_lname);
#else
        QAction *ima = new QAction(im_lname);
#endif
        ima->setData(im_name);
        actionMenu->addAction(actionGroup->addAction(ima));
        ima->setCheckable(true);
        if(curIm == im_name) {
            ima->setChecked(true);
        }
    }

    QObject::connect(actionGroup, &QActionGroup::triggered, onActionChanged);
    actionMenu->setStyleSheet("QMenu::item {padding:8px 32px;/*设置菜单项文字上下和左右的内边距，效果就是菜单中的条目左右上下有了间隔*/}");
    actionMenu->show();
    //监听属性变化
    DBusSingalHandler handler;
    QDBusConnection::sessionBus().connect(
                FCITX_DBUS_SERVICE, FCITX_DBUS_PATH,
                DBUS_PROP_INF, "PropertiesChanged", &handler,
                SLOT(propsChanged(QString,
                                  ArgPlaceholder, //或者直接QVariantMap: QMap<QString, QVariant>可直接和DBus的a{sv}互相转换
                                  QStringList)));



    a.exec();
    
}

